<?php

class BigfootStore {
  var $uri;
  var $metabox;
  var $sparql_service;
  var $jobs;
  var $contentbox;
  var $indexes;

  function BigfootStore($uri) {
    $this->uri = $uri;
    $this->init();
  }

  function init() {
    $this->metabox = new BigfootMetabox($this->uri . '/meta');
    $this->sparql_service = new BigfootSparqlService($this->uri . '/services/sparql?');
	$this->jobs = new BigfootJobs($this->uri.'/jobs');
	$this->contentbox = new BigfootContentBox($this->uri.'/items');
	$this->indexes = new BigfootIndexes($this->uri.'/indexes');
  }

  function get_metabox() {
    return $this->metabox;
  }
  function get_sparql_service() {
    return $this->sparql_service;
  }

  function get_jobs() {
	return $this->jobs;
  }
  
  function get($uri,$auth)
  {

	$request_factory = new HttpRequestFactory();
    $request = $request_factory->make( 'GET', $uri);

	if(!empty($auth) && isset($auth['username']) && isset($auth['password']))
	{
		$request->authenticate($auth['username'], $auth['password']);
	}
	return $request->execute();

  }
  

  function post($uri,$rdfxml,$mimetype,$auth)
  {

	$request_factory = new HttpRequestFactory();
    $request = $request_factory->make( 'POST', $uri);
    $request->set_content_type($mimetype);
    $request->set_body( $rdfxml );

	if(!empty($auth) && isset($auth['username']) && isset($auth['password']))
	{
		$request->authenticate($auth['username'], $auth['password']);
	}
	return $request->execute();

  }


  function put($uri,$rdfxml,$mimetype,$auth)
  {

	$request_factory = new HttpRequestFactory();
    $request = $request_factory->make( 'PUT', $uri);
    $request->set_content_type($mimetype);
    $request->set_body( $rdfxml );

	if(!empty($auth) && isset($auth['username']) && isset($auth['password']))
	{
		$request->authenticate($auth['username'], $auth['password']);
	}
	return $request->execute();

  }


}

/*****************************************************************************
*****************************************************************************/

class BigfootIndexes
{
  var $uri;
  var $request_factory;

  function BigfootIndexes($uri){
	  $this->uri = $uri;
  }

  function get($config_url, $username, $password){
	return BigfootStore::get($this->uri.'/'.$config_url, compact('username','password'));
  }

  function put($config_rdf, $username, $password){
		return BigfootStore::put($this->uri, $config_rdf, 'application/rdf+xml',  compact('username', 'password'));
	}
	
}

/*****************************************************************************
*****************************************************************************/


class BigfootJobs
{
	var $uri;
  var $request_factory;

  function BigfootJobs($uri) {
    $this->uri = $uri;
  }

  function drop_store($username, $password)
  {
		$drop_store_rdf = <<<_RDF_
		<rdf:RDF
		    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
		    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
		    xmlns:bf="http://schemas.talis.com/2006/bigfoot/configuration#" > 
		  <rdf:Description rdf:about="my:jobrequest">
		    <bf:jobType rdf:resource="http://schemas.talis.com/2006/bigfoot/configuration#ResetDataJob"/>
		    <bf:startTime>2007-05-02T14:14:00Z</bf:startTime>
		    <rdfs:label>Reset Data Job for {$this->uri}</rdfs:label>
		    <rdf:type rdf:resource="http://schemas.talis.com/2006/bigfoot/configuration#JobRequest"/>
		  </rdf:Description>
		</rdf:RDF>
_RDF_;
 		return BigfootStore::post($this->uri, $drop_store_rdf, 'application/rdf+xml',  compact('username', 'password'));
  }
  
}
class BigfootMetabox {
  var $uri;
  var $request_factory;

  function BigfootMetabox($uri) {
    $this->uri = $uri;
  }

  function apply_changeset($cs, $auth=array(), $versioned=true) {
    return $this->apply_changeset_rdfxml( $cs->to_rdfxml(), $auth, $versioned);
  }

  function save_rdfxml($rdf, $auth){
	return $this->apply_changeset_rdfxml($rdf,$auth,false);
  }

  function apply_changeset_rdfxml($rdfxml, $auth=array(), $versioned=true) {
    if (! isset( $this->request_factory) ) {
      $this->request_factory = new HttpRequestFactory();
    }
	$options= array();
	

	$uri = $this->uri;
	if($versioned) 
	{
		$uri.= '/changesets' ;
		$mimetype = "application/vnd.talis.changeset+xml";
	}
	else
	{
		$mimetype = "application/rdf+xml";
	}
	
	return BigfootStore::post($uri,$rdfxml,$mimetype,$auth);
  }
}


/*****************************************************************************
*****************************************************************************/
class BigfootContentbox {
  var $uri;
  var $request_factory;

  function BigfootContentbox($uri) {
    $this->uri = $uri;
  }
  
  function make_search_uri( $query, $max=10, $offset=0) {
    $uri = $this->uri . '?query=' . urlencode($query) . '&max=' . urlencode($max) . '&offset=' . urlencode($offset);  
    return $uri;
  }

  function search( $query, $max=10, $offset=0) {
    if (! isset( $this->request_factory) ) {
      $this->request_factory = new HttpRequestFactory();
    }
	$url = $this->make_search_uri($query, $max, $offset);
    $request = $this->request_factory->make( 'GET', $url );
    $response = $request->execute();
	return $response;
  }

  function search_to_triple_list( $query, $max=10, $offset=0 ) {
    $triples = array();

    $response = $this->search( $query, $max, $offset );
    require_once $_SERVER['DOCUMENT_ROOT']."/lib/arc/ARC_rdfxml_parser.php";
    $parser_args=array(
      "bnode_prefix"=>"genid",
      "base"=> $this->uri
    );
    $parser =new ARC_rdfxml_parser($parser_args);
    $triples = $parser->parse_data( $response->body );

    return $triples;
  }
}


/*****************************************************************************
*****************************************************************************/
class BigfootSparqlService {
  var $uri;
  var $request_factory;

  function BigfootSparqlService($uri) {
    $this->uri = $uri;
  }
  
  function describe( $uri ) {
    if (! isset( $this->request_factory) ) {
      $this->request_factory = new HttpRequestFactory();
    }

    $request = $this->request_factory->make( 'POST', $this->uri );
    $request->set_accept("application/rdf+xml");
    $request->set_content_type("application/x-www-form-urlencoded");

    if ( is_array( $uri ) ) {
      $request->set_body( "query=" . urlencode("DESCRIBE <" . implode('> <' , $uri) . ">") );
    }
    else {
      $request->set_body( "query=" . urlencode("DESCRIBE <$uri>") );
    }
    return $request->execute();
  }

  function describe_to_triple_list( $uri ) {
    $triples = array();

    $response = $this->describe( $uri );
    require_once $_SERVER['DOCUMENT_ROOT']."/lib/arc/ARC_rdfxml_parser.php";
    $parser_args=array(
      "bnode_prefix"=>"genid",
      "base"=> $this->uri
    );
    $parser =new ARC_rdfxml_parser($parser_args);
    $triples = $parser->parse_data( $response->body );

    return $triples;
  }

  function graph( $query ) {
    if (! isset( $this->request_factory) ) {
      $this->request_factory = new HttpRequestFactory();
    }
    $request = $this->request_factory->make( 'POST', $this->uri );
	 $request->set_body( "query=" . urlencode($query));
    $request->set_accept("application/rdf+xml");
    $request->set_content_type("application/x-www-form-urlencoded");
    return $request->execute();
  }

  function graph_to_triple_list($query ) {
    $triples = array();
    $response = $this->graph( $query );
    require_once $_SERVER['DOCUMENT_ROOT']."/lib/arc/ARC_rdfxml_parser.php";
    $parser_args=array(
      "bnode_prefix"=>"genid",
      "base"=> $this->uri
    );
    $parser =new ARC_rdfxml_parser($parser_args);
    $triples = $parser->parse_data( $response->body );
    return $triples;
  }

  function select( $query ) {
    if (! isset( $this->request_factory) ) {
      $this->request_factory = new HttpRequestFactory();
    }

    $request = $this->request_factory->make( 'POST', $this->uri );
    $request->set_accept("application/rdf+xml");
    $request->set_content_type("application/x-www-form-urlencoded");

    $request->set_body( "query=" . urlencode($query) );
    return $request->execute();
  }

  function select_to_array( $query ) {
    $results = array();
    $response = $this->select( $query );
    $results = $this->parse_select_results( $response->body );
    return $results;
  }

  function parse_select_results( $xml ) {
    $results = array();
    $reader = new XMLReader();    
    $reader->XML(trim($xml));

    $result = array();
    $bindingName = null;
    $binding = array();
    while ($reader->read()) {
      if ( $reader->name == 'result') {

        if ( $reader->nodeType == XMLReader::ELEMENT) {
          $result = array();
        }
        elseif ( $reader->nodeType == XMLReader::END_ELEMENT) {
          array_push( $results, $result);
          $result = array();
        }
      }
      elseif ( $reader->name == 'binding') {
        if ( $reader->nodeType == XMLReader::ELEMENT) {
          $bindingName = $reader->getAttribute("name");
          $binding = array();
        }
        elseif ( $reader->nodeType == XMLReader::END_ELEMENT) {
          $result[ $bindingName ] = $binding;
          $bindingName = null;
          $binding = array();
        }
      }
      elseif ( $reader->name == 'uri' && $reader->nodeType == XMLReader::ELEMENT) {
        $binding['type'] = 'uri';
        $value = '';
        while ($reader->read()) {
          if ($reader->nodeType == XMLReader::TEXT
            || $reader->nodeType == XMLReader::CDATA
            || $reader->nodeType == XMLReader::WHITESPACE
            || $reader->nodeType == XMLReader::SIGNIFICANT_WHITESPACE) {
             $value .= $reader->value;
          }
          else if ($reader->nodeType == XMLReader::END_ELEMENT) {
            break;
          }
        }  
        $binding['value'] = $value;
      }
      elseif ( $reader->name == 'literal' && $reader->nodeType == XMLReader::ELEMENT) {
        $binding['type'] = 'literal';
        $datatype = $reader->getAttribute("datatype");
        if ( $datatype ) {
          $binding['datatype'] = $datatype;
        } 
        $lang = $reader->getAttribute("xml:lang");
        if ( $lang ) {
          $binding['lang'] = $lang;
        } 
        $value = '';
        while ($reader->read()) {
          if ($reader->nodeType == XMLReader::TEXT
            || $reader->nodeType == XMLReader::CDATA
            || $reader->nodeType == XMLReader::WHITESPACE
            || $reader->nodeType == XMLReader::SIGNIFICANT_WHITESPACE) {
             $value .= $reader->value;
          }
          else if ($reader->nodeType == XMLReader::END_ELEMENT) {
            break;
          }
        }
        $binding['value'] = $value;
      }
      elseif ( $reader->name == 'bnode' && $reader->nodeType == XMLReader::ELEMENT) {
        $binding['type'] = 'bnode';
        $value = '';
        while ($reader->read()) {
          if ($reader->nodeType == XMLReader::TEXT
            || $reader->nodeType == XMLReader::CDATA
            || $reader->nodeType == XMLReader::WHITESPACE
            || $reader->nodeType == XMLReader::SIGNIFICANT_WHITESPACE) {
             $value .= $reader->value;
          }
          else if ($reader->nodeType == XMLReader::END_ELEMENT) {
            break;
          }
        }
        $binding['value'] = $value;
      }
    }  
    $reader->close();
    return $results;
  }


}


/*****************************************************************************
*****************************************************************************/
class BigfootMultiSparqlService {
  var $uri;
  var $request_factory;

  function BigfootMultiSparqlService($uri) {
    $this->uri = $uri;
  }
  
  function describe( $uri, $graphs=array() ) {
    if (! isset( $this->request_factory) ) {
      $this->request_factory = new HttpRequestFactory();
    }

    $request = $this->request_factory->make( 'POST', $this->uri );
    $request->set_accept("application/rdf+xml");
    $request->set_content_type("application/x-www-form-urlencoded");


    if ( is_array( $uri ) ) {
      $query = "DESCRIBE <" . implode('> <' , $uri) . ">";
    }
    else {
      $query = "DESCRIBE <$uri>";
    }

    foreach( $graphs as $graph_uri) {
      $query .= ' FROM <' . $graph_uri . '> ';
    }

    $request->set_body( "query=" . urlencode($query) );

    return $request->execute();
  }

  function describe_to_triple_list( $uri, $graphs=array() ) {
    $triples = array();

    $response = $this->describe( $uri, $graphs );
    require_once $_SERVER['DOCUMENT_ROOT']."/lib/arc/ARC_rdfxml_parser.php";
    $parser_args=array(
      "bnode_prefix"=>"genid",
      "base"=> $this->uri
    );
    $parser =new ARC_rdfxml_parser($parser_args);
    $triples = $parser->parse_data( $response->body );

    return $triples;
  }

  function graph( $query ) {
    if (! isset( $this->request_factory) ) {
      $this->request_factory = new HttpRequestFactory();
    }

    $request = $this->request_factory->make( 'GET', $this->uri );
    $request->set_accept("application/rdf+xml");
    $request->set_content_type("application/x-www-form-urlencoded");

    $request->set_body( "query=" . urlencode($query) );
    return $request->execute();
  }

  function graph_to_triple_list($query ) {
    $triples = array();
    $response = $this->graph( $query );
    require_once $_SERVER['DOCUMENT_ROOT']."/lib/arc/ARC_rdfxml_parser.php";
    $parser_args=array(
      "bnode_prefix"=>"genid",
      "base"=> $this->uri
    );
    $parser =new ARC_rdfxml_parser($parser_args);
    $triples = $parser->parse_data( $response->body );
    return $triples;
  }
}


/*****************************************************************************
*****************************************************************************/
class HttpResponse {
  var $status_code;
  var $headers;
  var $body;
  const HTTP = 'http://www.w3.org/2006/http#';
  const HTTP_HEADER = 'http://www.w3.org/2006/http-header#';

	function toHTML()
	{
		$html = '<div id="http-response-'.time().'" class="-http-Response"><h3>HTTP Response</h3><dl><dt>Status Code</dt><dd class="http-responseCode" title="http://www.w3.org/2006/http#'.htmlentities($this->status_code).'">'.htmlentities($this->status_code).'</dd>';
		foreach($this->headers as $k => $v) $html.='<dt>'.htmlentities($k).'</dt><dd>'.htmlentities($v).'</dd>';
		$html.='<dt>Body</dt><dd class="http-body">'.htmlentities($this->body).'</dd></dl></div>';
		return $html;
	}
	function toArray(){
		$resources = array(
			'_:response' => array(
					HTTP.'responseCode' => array(array('type'=>'uri','value'=>HTTP.$this->status_code)),
					HTTP.'body' => array(array('type'=>'literal','value'=> $this->body)),
				),
			);
		return $resources;
	}
}

/*****************************************************************************
*****************************************************************************/
class HttpRequest {
  var $method;
  var $uri;
  var $headers = array();
  var $client;
  var $body;
  var $auth;

  function HttpRequest($method, $uri) {
    $this->uri = $uri;
    $this->method = $method;
    $this->headers = array();
  	$this->options = array();
  	$this->auth = null;
  	$this->body = null;

  }


  function execute($options=array()) {
    $poster = curl_init($this->uri);

    if ($this->auth != null) {
      curl_setopt($poster, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
      curl_setopt($poster, CURLOPT_USERPWD, $this->auth);
    }
   // curl_setopt($poster, CURLOPT_VERBOSE, 1);


    curl_setopt($poster, CURLOPT_FRESH_CONNECT,TRUE);

    curl_setopt($poster, CURLOPT_RETURNTRANSFER,1);
    curl_setopt($poster, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($poster, CURLOPT_CONNECTTIMEOUT, 5);
    curl_setopt($poster, CURLOPT_TIMEOUT, 600);
    curl_setopt($poster, CURLOPT_HTTPHEADER, $this->get_headers() );
    curl_setopt($poster, CURLOPT_HEADER, 1);

    switch(strtoupper($this->method)) {
        case 'GET'  : break;
        case 'POST' : curl_setopt($poster, CURLOPT_POST, 1); break;
        default     : curl_setopt($poster, CURLOPT_CUSTOMREQUEST,strtoupper($this->method));
    }

    if ($this->body != null) {
      curl_setopt($poster, CURLOPT_POSTFIELDS, $this->body);
    }
    $raw_response = curl_exec($poster);
    $response_info = curl_getinfo($poster);
    $response_error = curl_error($poster);
    curl_close($poster);

    if ( $raw_response ) {
      list($response_code,$response_headers,$response_body) = $this->parse_response($raw_response);
    }
    else {
      $response_code = $response_info['http_code'];
      $response_body = "Request failed: " . $response_error;
      $response_headers = array();
    }

    $response = new HttpResponse();
    $response->status_code = $response_code;
    $response->headers = $response_headers;
    $response->body = $response_body;
    $response->info = $response_info;
    $response->request = $this;
    return $response;
  }

  function get_headers() {
    $flat_headers = array();
    foreach ($this->headers as $k=>$v) {
      $flat_headers[] = "$k: $v";
    }
    return $flat_headers;
  }

  function set_body($val) {
    $this->body = $val;
  }

  function get_body() {
    return $this->body;
  }

  function set_accept($val) {
    $this->headers['Accept'] = $val;
  }

  function set_content_type($val) {
    $this->headers['Content-Type'] = $val;
  }


function parse_response($response){
   /*
   ***original code extracted from examples at
   ***http://www.webreference.com/programming
                           /php/cookbook/chap11/1/3.html

   ***returns an array in the following format which varies depending on headers returned

       [0] => the HTTP error or response code such as 404
       [1] => Array
       (
           [Server] => Microsoft-IIS/5.0
           [Date] => Wed, 28 Apr 2004 23:29:20 GMT
           [X-Powered-By] => ASP.NET
           [Connection] => close
           [Set-Cookie] => COOKIESTUFF
           [Expires] => Thu, 01 Dec 1994 16:00:00 GMT
           [Content-Type] => text/html
           [Content-Length] => 4040
       )
       [2] => Response body (string)
*/

   do
     {
      if ( strstr($response, "\r\n\r\n") == FALSE) {
        $response_headers = $response;
        $response = '';
      }
      else {
       list($response_headers,$response) = explode("\r\n\r\n",$response,2);
      }
       $response_header_lines = explode("\r\n",$response_headers);

   // first line of headers is the HTTP response code
       $http_response_line = array_shift($response_header_lines);
       if (preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@',$http_response_line,
                     $matches)) {
         $response_code = $matches[1];
       }
       else
         {
           $response_code = "Error";
         }
     }
   while (preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@',$response));

   $response_body = $response;

   // put the rest of the headers in an array
   $response_header_array = array();
   foreach ($response_header_lines as $header_line) {
       list($header,$value) = explode(': ',$header_line,2);
       $response_header_array[strtolower($header)] = $value;
   }

   return array($response_code,$response_header_array,$response_body);
  }

  function set_auth($auth_string) {
    $this->auth = $auth_string;
  }

  function to_string() {
    $ret = strtoupper($this->method) . ' ' . $this->uri . "\n";
    foreach ($this->headers as $k=>$v) {
      $ret .= "$k: $v\n";
    }
    $ret .= "\n";
    $ret .= $this->get_body();

    return $ret;
  }

}

/*****************************************************************************
*****************************************************************************/
class HttpRequestFactory {
  function make( $method, $uri ) {
    return new HttpRequest( $method, $uri );
  }
}


?>